package com.quectel.sdk.dahua9100;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.quectel.base.tuple.Tuple2;
import com.quectel.base.tuple.Tuples;
import com.quectel.sdk.dahua9100.basemodel.FirstLoginResp;
import com.quectel.sdk.dahua9100.basemodel.LoginFirst;
import com.quectel.sdk.dahua9100.basemodel.LoginSecond;
import com.quectel.sdk.dahua9100.basemodel.SecondLoginResp;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.http.HttpRestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2022-11-08 13:30:00
 */
public class Dahua9100Requester {


    private static final Logger logger = LoggerFactory.getLogger(Dahua9100Requester.class);

    /**
     * 文档默认的是120s失效
     */
    private static final Cache<String, String> TOKEN_CACHE =
            CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();

    /**
     * cache
     * k1 host
     * k2 username
     */
    private static Function<Tuple2<String, String>, String> TOKEN_CACHE_FUNC = (t) ->
            "USER_ID:" + t.getT1() + ":" + t.getT2();

    private static final HttpRestUtils HTTP_REST_UTILS = HttpRestUtils.getTrustSSLInstance();

    private String username;
    private String password;
    private String host;

    // HTTP端口 8314 HTTPS端口 8320
    private Integer port = 8320;

    private Dahua9100Requester(String username, String password, String ip) {
        this.host = "https://" + ip + ":" + port;
        this.username = username;
        this.password = password;
    }


    public static Dahua9100Requester getInstance(String username, String password, String ip) {

        return new Dahua9100Requester(username, password, ip);
    }

    public String get(String path, Map<String, Object> params) {
        if (host == null) {
            throw new CheckErrorException("checked host " + this.host + " is not accessible");
        }
        return get(host, path, params);
    }

    /**
     * 重载git请求，事件获取请求host需要传入
     *
     * @param host
     * @param path
     * @param params
     * @return
     */
    public String get(String host, String path, Map<String, Object> params) {
        if (this.host == null) {
            throw new CheckErrorException("checked host " + this.host + " is not accessible");
        }
        List<NameValuePair> paramList = new ArrayList<>();
        if (params != null) {
            Set<Map.Entry<String, Object>> entries = params.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                paramList.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
            }
        }

        String token = tokenReq();
        if (StringUtils.isBlank(token)) {
            throw new CheckErrorException("token req error.");
        }

        Map<String, String> header = new HashMap<>();
        header.put("X-Subject-Token", token);

        return HTTP_REST_UTILS.get(host + path, paramList, header, new TypeReference<String>() {
        }).getRight();
    }

    public String post(String path, Object params) {
        if (this.host == null) {
            throw new CheckErrorException("checked host " + this.host + " is not accessible");
        }

        String body = null;
        if (params != null) {
            body = params instanceof String ? params.toString() : JacksonUtils.toJsonString(params);
        }

        String token = tokenReq();
        if (StringUtils.isBlank(token)) {
            throw new CheckErrorException("token req error.");
        }

        Map<String, String> header = new HashMap<>();
        header.put("X-Subject-Token", token);
        return HTTP_REST_UTILS.post(host + path, body, header, new TypeReference<String>() {
        }).getRight();
    }

    private String tokenReq() {
        return TOKEN_CACHE.asMap().computeIfAbsent(TOKEN_CACHE_FUNC.apply(Tuples.of(host, username)), p -> {
            try {
                LoginFirst fir = new LoginFirst(username);

                final String path = "/videoService/accounts/authorize";
                Pair<Integer, String> firResp = HTTP_REST_UTILS.post(host + path, fir, null, new TypeReference<String>() {
                });
                FirstLoginResp loginResp = JacksonUtils.parse(firResp.getRight(), FirstLoginResp.class);

                LoginSecond snd = new LoginSecond();
                snd.setUserName(username);
                snd.setClientType(fir.getClientType());
                snd.setRandomKey(loginResp.getRandomKey());
                snd.setEncryptType("MD5");
                String signature = snd.calcSignature(password, loginResp.getRealm());
                snd.setSignature(signature);
                Pair<Integer, String> sdnResp = HTTP_REST_UTILS.post(host + path, snd, null, new TypeReference<String>() {
                });

                return JacksonUtils.parse(sdnResp.getRight(), SecondLoginResp.class).getToken();
            } catch (Exception e) {
                logger.error("大华会话请求异常", e);
            }
            return null;
        });
    }

}
